<script setup lang="ts">
import { QuestionFilled } from "@element-plus/icons-vue"
import { ElMessage, UploadProps } from "element-plus"
import option from '@/utils/echarts/threeDimension'
let option2D = ref(option)
let { proxy } = getCurrentInstance() as any
let commitObject = ref({
  runId: '',
  filePath: '',
  sortOrder: 'desc',
  dataType: 'grid_search',
  tableName: '',
  compositeConfig: [] as any,
  features: [] as any,
  labels: [] as any,
  returnType: '',
  refer: ''
})
let currentPage = ref(1)
let pageSize = ref(10)
let size = 'default'
let total = ref(0)

let params = {
  runName: '',
  pageNo: currentPage.value,
  pageSize: pageSize.value,
  isAsc: false,
  orderBy: "runName"
}
let activeName = ref('1')
let runName = ref()
let search = ref('')
let modelName = ref()
let input = ref({} as any)
let isDownload = ref()
let downloadData = ref()
let tableData = ref()
let selectRow = ref({
  dataName: "",
  modelName
})
let dialogTableVisible = ref(false)
let stp = ref(1)
let d2 = ref()

const searchModelSet = () => {
  params.runName = search.value
  query()
}
const resetData = () => {
  params.runName = ''
  query()
}
const switchInputParams = (val: any) => {
  switch (val) {
    case 0:
      break
    case 1:
      break
    case 2:
      break
  }
}

function query() {
  let url = "/admin-api/wpes/runResult/page"
  proxy.$http.get(url, { params }).then((v) => {
    if (v.data.code == 0) {
      total.value = v.data.data.total
      tableData.value = v.data.data.list
    }
  })
}

const handleCurrentChange = (e) => {
  params.pageNo = e
  query()
}

const chooseModel = () => {
  dialogTableVisible.value = true
  query()
}
const getRowDataByClick = (row: any) => {
  const { runId, status, id } = row
  if (status == 'FAILED' || status == 'RUNNING' || status == 'ERROR') {
    ElMessage.warning('该模型不是完成或者终止状态，不能用于预测！')
    return;
  } else {
    let url = '/admin-api/wpes/runResult/get'
    let params = { id }
    proxy.$http.get(url, { params }).then((v) => {
      // console.log(v)
      if (v.data.code == 0) {
        commitObject.value.features = []
        ElMessage.success(`已选择id为${runId},训练名称为${v.data.data.runName}的模型`)
        runName.value = v.data.data.runName
        let config = JSON.parse(v.data.data.netConfig);
        commitObject.value.runId = runId
        commitObject.value.features = config.features
        commitObject.value.filePath = ""
        commitObject.value.labels = config.labels
        dialogTableVisible.value = false
        config.features.forEach((i) => {
          input.value[i] = [] as any
        })
      }
    }).catch((e) => {
      console.log(e)
      ElMessage.warning('本次运行结果有错误，无法查看！')
    })
  }
}
function calculateStep(min: number, max: number) {
  if (max < min || max == min) {
    ElMessage.warning('上限必须大于下限！')
    return -1;
  }
  let n = commitObject.value.features.length || 1; // 可以根据需要修改 n 的值
  let diff = (max - min) / Math.floor(Math.pow(10000, 1 / n));
  // let diff = (max - min) / 15
  if (diff < 0.1) {
    stp.value = 0.0001
    if (Number(diff.toFixed(4)) === 0) {
      return 0.0001
    }
    return diff.toFixed(4)
  } else if (0.1 <= diff && diff < 1) {
    stp.value = 0.01
    return diff.toFixed(2)
  }
  if (diff > 1) {
    stp.value = 0.1
    return diff.toFixed(1)
  }
}

/* @提交得到预测结果 */
const commitModelResult = () => {
  if (commitObject.value.returnType == '' || commitObject.value.refer == '') {
    ElMessage.info('请选择预测结果呈现方式以及趋势参照！！！')
    return
  } else {
    //如果全部为空，或者部分为空的输入参数，就提示
    let bol = Object.keys(input.value).some(k => {
      return input.value[k].length == 0 || input.value[k].length != 3 || input.value[k].some(s => isNaN(Number(s)))
    })
    // console.log(bol, input.value)
    if (bol) {
      ElMessage.info('请输入完整参数后预测！！！')
      return
    } else {
      let url = '/admin-api/wpes/model/bpnnPredict'
      if (Object.entries(input.value).length > 0) {
        commitObject.value.compositeConfig = []
        Object.entries(input.value).forEach((item: any, index) => {
          let s = calculateStep(item[1][0] * 1, item[1][1] * 1)
          commitObject.value.compositeConfig.push({
            featureName: item[0],
            start: item[1][0],
            end: item[1][1],
            step: item[1][2] ?? s,
          })
        })
      }
      commitObject.value.compositeConfig.forEach((c) => {
        if (c.end * 1 < c.start * 1) {
          console.log(1)
          ElMessage.error('上限必须大于下限！')
          return;
        }
      })
      proxy.$http.post(url, commitObject.value, { headers: { responseType: 'blob' } }).then((p) => {
        if (p.data.code == 200 || p.status == 200) {
          ElMessage.success('预测成功，等待结果展示！')
          if (commitObject.value.returnType == 'file') {
            let data = "\ufeff" + p.data
            //  前面加上这个 "\ufeff"  就不乱码了！！！？
            console.log(data)
            const a = document.createElement("a")
            const blob = new Blob([data], { type: 'text/csv,charset=UTF-8' })
            const href = window.URL.createObjectURL(blob)
            a.href = href
            let fileName = "predict.csv"
            a.download = fileName
            ElMessage.success("下载正在进行中，请稍后！")
            document.body.appendChild(a)
            a.click()
            document.body.removeChild(a)
            window.URL.revokeObjectURL(href)
            return
          }
          let { dimMsg, features, predictLabels } = p.data.data
          let set: string[] = [];
          let dimMsgKeys = Object.keys(dimMsg)
          let featuresKeys = Object.keys(features)
          let predictLabelsKeys = Object.keys(predictLabels)
          let predictLabelsValue = Object.values(predictLabels) as any[]
          let dataSource = [];
          predictLabelsKeys.forEach(k => {
            option2D.value.dataset.dimensions.push(k)
            // 存入对应的key  x=> 'x' y => 'y'
            set.push(k)
          })
          dimMsgKeys.forEach(k => { //   x y z
            option2D.value.dataset.dimensions.push(k)
            set.push(k)
          })
          featuresKeys.forEach(k => {
            option2D.value.dataset.dimensions.push(k)
            set.push(k)
          })
          //这里主要是处理三维图的encode x 对应于x轴线 y 对应y轴 z 对应z轴，详情见三维图代码解释 @/utils/echarts下
          dataSource.push(set)
          if (predictLabelsValue.length > 0) {
            predictLabelsValue.forEach(p => {
              p.forEach((item: number, index: number) => {
                let t = [] as any;
                predictLabelsKeys.forEach(k => {
                  t.push(predictLabels[k][index])
                })
                dimMsgKeys.forEach(k => {
                  t.push(dimMsg[k][index])
                })
                featuresKeys.forEach(k => {
                  t.push(features[k][index])
                })
                dataSource.push(t)
              })
            })

            //对接数据源
            // console.log(dataSource)
            option2D.value.dataset.source = dataSource
            // console.log(dataSource)
            let maxmin = findMinMax(dataSource)
            let idx = set.findIndex(s => {
              return s == commitObject.value.refer
            })
            // console.log(maxmin, idx, set)
            if (idx >= 0) {
              option2D.value.visualMap[0].text = [set[idx]]
              option2D.value.visualMap[0].min = maxmin[idx].min
              option2D.value.visualMap[0].max = maxmin[idx].max
              option2D.value.visualMap[0].dimension = idx
              let e = []
              set.forEach((s, i) => {
                // console.log(featuresKeys.length, s)
                if (featuresKeys.length > 3) {
                  option2D.value.grid3D.axisTick.show = false
                  option2D.value.grid3D.axisLabel.show = false
                  if (['x', 'y', 'z'].includes(s)) {
                  } else {
                    e.push(i)
                  }
                } else {
                  e.push(i)
                }
              })
              // console.log(e, set)
              option2D.value.series[0].encode.tooltip = e
            }
            proxy.$dom && proxy.$dom.setOption(option2D.value)
          } else { // 输出数组为空

          }
        }
      })
    }
  }

}

function findMinMax(arr) {
  const result = [];

  // 获取子元素数组的长度
  const length = arr[0].length;

  // 遍历每个子元素数组下标
  for (let i = 0; i < length; i++) {
    let min = arr[1][i];
    let max = arr[1][i];

    // 遍历数组，找出每个子元素下标一样的最大值和最小值
    for (let j = 1; j < arr.length; j++) {
      if (arr[j][i] < min) {
        min = arr[j][i];
      }
      if (arr[j][i] > max) {
        max = arr[j][i];
      }
    }

    // 将结果添加到结果数组中
    result.push({ max, min });
  }

  return result;
}
const modify = (inputVal: FocusEvent) => {
  if (isNaN(Number((inputVal.target as HTMLInputElement).value))) {
    ElMessage.warning('请输入大于0的数字');
    (inputVal.target as HTMLInputElement).value = ''
    return;
  } else if (Number((inputVal.target as HTMLInputElement).value) < 0) {
    ElMessage.warning('请输入大于0的数字');
    (inputVal.target as HTMLInputElement).value = ''
  }
}
const resetStep = (v, k) => {
  if (v.length >= 2 && v.every(vv => !isNaN(Number(vv)))) {
    let step = calculateStep(Number(v[0]), Number(v[1]))
    if (step == -1) {
      input.value[k][1] = ''
      input.value[k][2] = ''
      return;
    }
    //console.log(step, input.value)
    input.value[k][2] = step + ''
  }
  else {
    input.value[k][2] = ''
    ElMessage.info('请输入完整的参数后预测！！！')
  }
}
const setStep = (v, k) => {
  // console.log(v, k)
  let min = input.value[k][0]
  let max = input.value[k][1]
  let minStep = calculateStep(min, max)
  let diff = max - min
  let vn = Number(v)
  if (vn <= Number(minStep) || vn > diff) {
    input.value[k][2] = minStep
    ElMessage.warning('step不可小于生成的最小step，亦不可大于最大step(max - min)!')
  } else {
    input.value[k][2] = vn
  }
  // console.log(input.value)
}
let returnType_options = ref([
  { label: '图表展示', value: 'display' },
  { label: '文件下载', value: 'file' },
])
onMounted(() => {
  if (d2.value) {
    proxy.$dom = proxy.$echarts.init(d2.value)
    proxy.$dom && proxy.$dom.setOption(option2D.value)
  }
})
let description = ref('系统将为该特征（或称为字段）赋予一系列可能的取值，分别是：下限、下限+（1×步伐）、下限+（2×步伐）、...、上限。该字段的取值将会与其他字段进行组合，从而合成样本。模型将会对样本的标签进行预测。')
</script>
<template>
  <div h-full w-full uno-padding-10>
    <div class="css_cx" h-full w-full py-5>
      <div class="css_left" h-full style="width: 28%">
        <p class="css_biaot" />
        <div class="css_tite">
          {{ selectRow.modelName ? " " + selectRow.modelName : "" }}
        </div>
        <el-button type="primary" style="margin-top: 5px; width: 140px" @click="chooseModel">选择模型 </el-button>

        <el-dialog v-model="dialogTableVisible" width="1350" title="模型选择">
          <div class="search flex items-end">
            <el-input class="!w-45 !h-8" v-model="search" size="small" @blur="chooseModel" placeholder="输入模型名称关键字查询" />
            <el-button class="ml-3" @click="searchModelSet">查询</el-button>
            <el-button @click="resetData">重置</el-button>
          </div>
          <el-table ref="multipleTableRef" @row-click="getRowDataByClick" :data="tableData" height="650"
            style="font-size: 15px">
            <el-table-column width="210" prop="runId" align="center" label="模型id" />
            <el-table-column width="110" :show-overflow-tooltip="true" prop="runName" label="模型名称">
            </el-table-column>
            <el-table-column width="210" :show-overflow-tooltip="true" prop="description" align="center" label="模型描述" />
            <el-table-column prop="duration" width="180" align="center" label="持续时间" />
            <el-table-column width="110" prop="status" align="center" label="状态"> </el-table-column>
            <el-table-column prop="startTime" align="center" width="250px" label="创建时间" sortable />
            <el-table-column prop="endTime" align="center" width="250px" label="结束时间" sortable />
            <el-table-column prop="lifecycleStage" align="center" label="操作"> </el-table-column>
          </el-table>
          <el-pagination v-model:current-page="currentPage" v-model:page-size="pageSize" :size="size" :disabled="false"
            :background="true" layout="prev, pager, next, jumper" :total="total"
            @current-change="handleCurrentChange" />
        </el-dialog>
        <div style="font-size: 16px" class="css_biaot">输入参数</div>

        <el-radio-group v-model="activeName" @change="switchInputParams">
          <el-radio-button label="1" name="'1'">范围值</el-radio-button>
          <!-- <el-radio-button label="2" name="2">上传参数</el-radio-button> -->
        </el-radio-group>

        <div mt-3 class="m-h-56 overflow-y-scroll">
          <div v-for="(key, index) in commitObject.features" pb-4>
            <div class="css_biaoti flex" pb-2>
              {{ key }}
              <el-popover :width="300" v-if="index == 0"
                popper-style="box-shadow: rgb(14 18 22 / 35%) 0px 10px 38px -10px, rgb(14 18 22 / 20%) 0px 10px 20px -15px; padding: 20px;">
                <template #reference>
                  <div class="flex items-center gap-1.5">

                    <el-icon class="scale-80">
                      <QuestionFilled />
                    </el-icon>
                  </div>
                </template>
                <template #default>
                  <div class="demo-rich-conent" style="display: flex; gap: 16px; flex-direction: column">
                    <div>
                      <p class="demo-rich-content__name" style="margin: 0; font-weight: 500">
                        {{ description }}
                      </p>
                    </div>
                  </div>
                </template>
              </el-popover>
            </div>
            <div class="inputs">
              <el-input min="0" :step="stp" @blur="modify" class="!w-30" v-model="input[key][0]" type="number"
                placeholder="请输入下限" />
              <el-input min="0" @blur="modify" @change="resetStep(input[key], key)" class="!w-30 "
                v-model="input[key][1]" type="number" :step="stp" placeholder="请输入上限" />
              <el-input min="0" @blur="modify" @change="setStep($event, key)" class="!w-25 step " :step="stp"
                v-model="input[key][2]" type="number" placeholder="请输入步长" />
            </div>
          </div>
          <div class="showWay">
            <label for="showWay" class="mr-3">呈现方式</label>
            <el-select v-model="commitObject.returnType" placeholder="请选择">
              <el-option v-for="item in returnType_options" :key="item.label" :label="item.label" :value="item.value">
              </el-option>
            </el-select>
          </div>
          <div class="showReferece mt-3">
            <label for="showWay" class="mr-3">趋势参照</label>
            <el-select v-model="commitObject.refer" placeholder="请选择">
              <el-option v-for="item in commitObject.labels" :key="item" :label="item" :value="item">
              </el-option>
            </el-select>
          </div>
          <el-button v-if="commitObject.features.length > 0" ml-30 mt-8 style="" type="primary"
            @click="commitModelResult">预测结果</el-button>
          <el-button v-if="isDownload" style="margin: 15px 0px" type="primary" @click="downloadData">下载数据</el-button>
        </div>
        <div class="choosedModel mt-5" v-if="commitObject.runId !== ''">
          <el-card shadow="always">
            当前已选择模型名称:{{ runName }} <br /> id:{{ commitObject.runId }}
          </el-card>
        </div>
      </div>
      <!-- 三维散点图表 -->
      <div class="css_Rig">
        <div class="css_flexrom">
          <div class="css_biaoti">预测模型</div>
        </div>
        <div class="css_Rig1 flex flex-col">
          <div id="main" class="w-full h-full p-3" ref="d2"></div>
          <!-- <div class="table flex-1">2</div> -->
        </div>
      </div>

    </div>
  </div>
</template>
<style lang="scss" scoped>
@import "@/styles/modelPredict.scss";

:deep(.el-dialog__body) {
  padding: 10px 25px 35px 25px;
}

.avatar-uploader {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;

  :deep(.el-upload) {
    width: 50%;
    height: 35%;
    border: 1px dashed var(--el-border-color);
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);

    &:hover {
      border-color: var(--el-color-primary);
    }
  }
}
</style>
